package com.lry.proxy;

import com.lry.protocol.RpcInvocation;
import com.lry.router.Router;
import com.lry.rpc.netty.client.ClientCache;
import com.lry.util.CollectionUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

@Slf4j
public abstract class AbstractProxy implements Proxy {


    protected Object enhance(Map<String,Object> att, Method method, Object[] args, Class clazz, Router router) throws Throwable {

        RpcInvocation rpcInvocation = new RpcInvocation();
        rpcInvocation.setTargetMethod(method.getName());
        rpcInvocation.setAttachments(att);
        RpcCallback rpcCallback = null;

        if(args[args.length-1] instanceof RpcCallback){
            rpcCallback = (RpcCallback) args[args.length-1];
        }


        //同步流程
        if(null==rpcCallback){
            rpcInvocation.setTargetServiceName(clazz.getName());
            rpcInvocation.setArgTypes(method.getParameterTypes());
            rpcInvocation.setArgs(args);
            return invoke(router,rpcInvocation,null);
        }
        //异步流程
        else{
            rpcInvocation.setTargetServiceName(clazz.getInterfaces()[0].getName());
            rpcInvocation.setArgTypes(classes(method.getParameterTypes()));
            rpcInvocation.setArgs(objs(args));
            return invoke(router,rpcInvocation,rpcCallback);
        }
    }

    private Object invoke(Router router,RpcInvocation rpcInvocation,RpcCallback rpcCallback) throws TimeoutException {
        List<Invoker> invokers = ClientCache.getInvokers(rpcInvocation);
        if(CollectionUtils.isEmpty(invokers)){
            log.error("invokers is null");
            return null;
        }
        RpcInvoker invoker = (RpcInvoker) router.select(invokers,rpcInvocation);
        invoker.setRpcCallback(rpcCallback);
        return invoker.invoke(rpcInvocation);
    }

    private Class[] classes(Class[] objs){
        if(objs.length<=1){
            return new Class[0];
        }
        Class[] robjs = new Class[objs.length-1];

        for(int i=0;i<objs.length-1;i++){
            robjs[i] = objs[i];
        }
        return robjs;
    }

    private Object[] objs(Object[] objs){
        if(objs.length<=1){
            return new Object[0];
        }
        Object[] robjs = new Object[objs.length-1];

        for(int i=0;i<objs.length-1;i++){
            robjs[i] = objs[i];
        }
        return robjs;
    }
}
